package com.lighting.shortlink.project.mq.idempotent;

import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 消息队列幂等处理器
 * @author : lighting
 */
@Component
@RequiredArgsConstructor
public class MessageQueueIdempotentHandler {

    private final StringRedisTemplate stringRedisTemplate;

//    消息幂等键的统一前缀，用 : 分割在 redis 中形成清晰的层次结构
    private static final String IDEMPOTENT_KEY_PREFIX = "short-link:idempotent:";


    /**
     * 判断当前消息是否消费过
     * @param messageId 消息唯一标识
     * @return 消息是否被消费了 true：消费了；false：未消费
     */
    public boolean isMessageProcessed(String messageId){
        String key = IDEMPOTENT_KEY_PREFIX + messageId;//统一前缀 + 消息ID 拼接成唯一的键
//     seIfAbsent() 方法用于设置一个键值对
//     如果键不存在，就设置键为 "0" 表示在处理了，并设置过期时间为2分钟
//     如果设置成功，返回 1 true，表示消息未被处理过
//     如果设置失败（即键已存在），则返回 0 false，表示消息已经有在处理了
        return Boolean.FALSE.equals(stringRedisTemplate.opsForValue().setIfAbsent(key,"0",2, TimeUnit.MINUTES));
    }

    /**
     * 判断消息消费流程是否执行完成
     * @param messageId 消息唯一标识
     * @return 消息是否执行完成
     */
    public boolean isAccomplish(String messageId) {
        String key = IDEMPOTENT_KEY_PREFIX + messageId;
//        opsForValue().get(key) 方法用于获取键 key 对应的值。
//        如果这个值是 "1"，则表示消息已经被成功处理，方法返回 true；
//        如果值不是 "1" 或键不存在，则表示消息未被处理或未完成处理，方法返回 false。
        return Objects.equals(stringRedisTemplate.opsForValue().get(key), "1");
    }

    /**
     * 设置消息流程执行完成
     *
     * @param messageId
     */
    public void setAccomplish(String messageId) {
        String key = IDEMPOTENT_KEY_PREFIX + messageId;
//        把 key 的 value 设置为 1 表示消息已经处理完毕
        stringRedisTemplate.opsForValue().set(key, "1", 2, TimeUnit.MINUTES);
    }

    /**
     * 如果消息处理遇到异常情况，删除幂等标识
     *
     * @param messageId 消息唯一标识
     */
    public void delMessageProcessed(String messageId) {
        String key = IDEMPOTENT_KEY_PREFIX + messageId;
        stringRedisTemplate.delete(key);
    }
}
